{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/OJB-Quantum/Maxwell-Boltzmann-Distribution/blob/main/lin_alg_review.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "6a2ed6ad-d29f-4df1-9a98-22a5aa9582ef",
      "metadata": {
        "id": "6a2ed6ad-d29f-4df1-9a98-22a5aa9582ef"
      },
      "outputs": [],
      "source": [
        "# This script requires numpy, to install it use\n",
        "# pip install numpy\n",
        "import numpy as np\n",
        "from numpy import matrix\n",
        "import math"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "eb887ed4-a053-4dd9-86dc-3ac5318c964f",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "eb887ed4-a053-4dd9-86dc-3ac5318c964f",
        "outputId": "d2f3f934-cccc-4c90-dddf-c45600fa1629"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Matrix U is unitary.\n",
            "Matrix H is Hermitian.\n",
            "The eigenvalues are [3.+0.j 1.+0.j]\n",
            "The spectral decomposition is [[2.+0.j 0.+1.j]\n",
            " [0.-1.j 2.+0.j]]\n",
            "If identity, closure property is observed: [[1.+0.j 0.+0.j]\n",
            " [0.+0.j 1.+0.j]]\n",
            "Dot product is invariant under the unitary transformation.\n"
          ]
        }
      ],
      "source": [
        "# Function to check if a matrix is unitary\n",
        "def is_unitary(matrix):\n",
        "    \"\"\"\n",
        "    Checks if the matrix is unitary.\n",
        "    A matrix U is unitary if U * U.H = I where U.H is the conjugate transpose.\n",
        "    \"\"\"\n",
        "    identity_matrix = np.eye(matrix.shape[0])\n",
        "    product = np.dot(matrix, np.conjugate(matrix).T)\n",
        "    return np.allclose(product, identity_matrix)\n",
        "\n",
        "# Function to check if a matrix is Hermitian\n",
        "def is_hermitian(matrix):\n",
        "    \"\"\"\n",
        "    Checks if the matrix is Hermitian.\n",
        "    A matrix H is Hermitian if H = H.H, where H.H is the conjugate transpose.\n",
        "    \"\"\"\n",
        "    return np.allclose(matrix, np.conjugate(matrix).T)\n",
        "\n",
        "# Function to verify that dot product doesn't change under unitary transformation\n",
        "def verify_dot_product_invariance(U, v1, v2):\n",
        "    \"\"\"\n",
        "    Verifies that the dot product between two vectors v1 and v2 remains unchanged\n",
        "    when transformed by a unitary matrix U.\n",
        "    \"\"\"\n",
        "    # Original dot product in the original basis\n",
        "    dot_original = np.dot(np.conjugate(v1).T, v2)\n",
        "\n",
        "    # Change of basis: new vectors are Uv1 and Uv2\n",
        "    v1_new = np.dot(U, v1)\n",
        "    v2_new = np.dot(U, v2)\n",
        "\n",
        "    # Dot product in the new basis\n",
        "    dot_new = np.dot(np.conjugate(v1_new).T, v2_new)\n",
        "\n",
        "    # Check if the dot products are approximately equal\n",
        "    return np.allclose(dot_original, dot_new)\n",
        "\n",
        "# Function to diagonalize an input matrix M\n",
        "# evector = eigenvector\n",
        "# eigenvals = eigenvalues\n",
        "# M = presumed matrix represented as a variable\n",
        "def eigenval_calculator(M):\n",
        "    eigenvals = np.linalg.eigvals(M)\n",
        "    return eigenvals\n",
        "\n",
        "def closure(M):\n",
        "    evalues, evectors = np.linalg.eig(M)\n",
        "    closure = np.zeros((len(M), len(M)))\n",
        "    # print(evalues)\n",
        "    # print(evectors)\n",
        "    for i in range(len(M)):\n",
        "        closure = closure + np.outer(evectors[:,i], evectors[:,i].conj())\n",
        "    return closure\n",
        "\n",
        "# Function to perform spectral decomposition of an input matrix M\n",
        "def spectral(M):\n",
        "    evalues, evectors = np.linalg.eig(M)\n",
        "    M_spec = np.zeros((len(M), len(M)))\n",
        "    #print(evalues)\n",
        "    #print(evectors)\n",
        "    for i in range(len(M)):\n",
        "        M_spec = M_spec + evalues[i] * np.outer(evectors[:,i], evectors[:,i].conj())\n",
        "    return M_spec\n",
        "\n",
        "# Example usage\n",
        "if __name__ == \"__main__\":\n",
        "    # Define a unitary matrix U\n",
        "    U = np.array([[1/np.sqrt(2), 1/np.sqrt(2)], [1/np.sqrt(2), -1/np.sqrt(2)]])\n",
        "\n",
        "    # Define a Hermitian matrix H\n",
        "    H = np.array([[2, 1j], [-1j, 2]])\n",
        "\n",
        "    # Define two vectors v1 and v2\n",
        "    v1 = np.array([1, 0])\n",
        "    v2 = np.array([0, 1])\n",
        "\n",
        "    # # Check if U is unitary\n",
        "    if is_unitary(U):\n",
        "        print(\"Matrix U is unitary.\")\n",
        "    else:\n",
        "        print(\"Matrix U is not unitary.\")\n",
        "\n",
        "    # # Check if H is Hermitian\n",
        "    if is_hermitian(H):\n",
        "        print(\"Matrix H is Hermitian.\")\n",
        "    else:\n",
        "        print(\"Matrix H is not Hermitian.\")\n",
        "\n",
        "    # Compute eigenvalues\n",
        "    eigenvalues = eigenval_calculator(H)\n",
        "    print(f'The eigenvalues are {eigenvalues}')\n",
        "\n",
        "    # eigenvalues = eigenval_calculator(np.matmul(H,H))\n",
        "    # print(f'The eigenvalues are {eigenvalues}')\n",
        "\n",
        "    # Compute eigenvalues and eigenvectors for spectral decomp.\n",
        "    H_spec = spectral(H)\n",
        "    print(f'The spectral decomposition is {H_spec}')\n",
        "    clos = closure(H)\n",
        "    print(f'If identity, closure property is observed: {clos}')\n",
        "\n",
        "    # Verify that dot product remains invariant under U\n",
        "    if verify_dot_product_invariance(U, v1, v2):\n",
        "        print(\"Dot product is invariant under the unitary transformation.\")\n",
        "    else:\n",
        "        print(\"Dot product changes under the unitary transformation.\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "080bad3b-bad8-4537-99b4-1e9e55190bae",
      "metadata": {
        "id": "080bad3b-bad8-4537-99b4-1e9e55190bae"
      },
      "outputs": [],
      "source": [
        "# Define an Observable O\n",
        "O = np.array([[0, 1], [1, 0]])\n",
        "\n",
        "# Using the observable above, compute: <psi|O|psi> and <psi'|O'|psi'>\n",
        "# where |psi> are the eigenvectors of H and |psi'> = U|psi> and O' = U*O*U'\n",
        "# Verify that the matrix equals 1."
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Function to check if a matrix is unitary\n",
        "def is_unitary(matrix):\n",
        "    \"\"\"\n",
        "    Checks if the matrix is unitary.\n",
        "    A matrix O is unitary if U * U.H = I where U.H is the conjugate transpose.\n",
        "    \"\"\"\n",
        "    identity_matrix = np.eye(matrix.shape[0])\n",
        "    product = np.dot(matrix, np.conjugate(matrix).T)\n",
        "    return np.allclose(product, identity_matrix)\n",
        "\n",
        "# Function to check if a matrix is Hermitian\n",
        "def is_hermitian(matrix):\n",
        "    \"\"\"\n",
        "    Checks if the matrix is Hermitian.\n",
        "    A matrix H is Hermitian if H = H.H, where H.H is the conjugate transpose.\n",
        "    \"\"\"\n",
        "    return np.allclose(matrix, np.conjugate(matrix).T)\n",
        "\n",
        "# Function to verify that dot product doesn't change under unitary transformation\n",
        "def verify_dot_product_invariance(U, v1, v2):\n",
        "    \"\"\"\n",
        "    Verifies that the dot product between two vectors v1 and v2 remains unchanged\n",
        "    when transformed by a unitary matrix U.\n",
        "    \"\"\"\n",
        "    # Original dot product in the original basis\n",
        "    dot_original = np.dot(np.conjugate(v1).T, v2)\n",
        "\n",
        "    # Change of basis: new vectors are Uv1 and Uv2\n",
        "    v1_new = np.dot(U, v1)\n",
        "    v2_new = np.dot(U, v2)\n",
        "\n",
        "    # Dot product in the new basis\n",
        "    dot_new = np.dot(np.conjugate(v1_new).T, v2_new)\n",
        "\n",
        "    # Check if the dot products are approximately equal\n",
        "    return np.allclose(dot_original, dot_new)\n",
        "\n",
        "# Function to diagonalize an input matrix M\n",
        "# evector = eigenvector\n",
        "# eigenvals = eigenvalues\n",
        "# M = presumed matrix represented as a variable\n",
        "def eigenval_calculator(M):\n",
        "    eigenvals = np.linalg.eigvals(M)\n",
        "    return eigenvals\n",
        "\n",
        "def closure(M):\n",
        "    evalues, evectors = np.linalg.eig(M)\n",
        "    closure = np.zeros((len(M), len(M)))\n",
        "    # print(evalues)\n",
        "    # print(evectors)\n",
        "    for i in range(len(M)):\n",
        "        closure = closure + np.outer(evectors[:,i], evectors[:,i].conj())\n",
        "    return closure\n",
        "\n",
        "# Function to perform spectral decomposition of an input matrix M\n",
        "def spectral(M):\n",
        "    evalues, evectors = np.linalg.eig(M)\n",
        "    M_spec = np.zeros((len(M), len(M)))\n",
        "    #print(evalues)\n",
        "    #print(evectors)\n",
        "    for i in range(len(M)):\n",
        "        M_spec = M_spec + evalues[i] * np.outer(evectors[:,i], evectors[:,i].conj())\n",
        "    return M_spec\n",
        "\n",
        "#__________________________________________________________________________________________________________________________\n",
        "\n",
        "# Using the observable above, compute: <psi|O|psi> and <psi'|O'|psi'>, where |psi> are the eigenvectors of H and |psi'> = U|psi> and O' = U*O*U'.\n",
        "# Should get two numbers (real), 1 number each for the examples.\n",
        "# Verify that the matrix equals 1.\n",
        "\n",
        "# Example usage\n",
        "if __name__ == \"__main__\":\n",
        "    # Define an Observable O\n",
        "    O = np.array([[0, 1], [1, 0]])\n",
        "\n",
        "    # Define two vectors v1 and v2\n",
        "    v1 = np.array([1, 0])\n",
        "    v2 = np.array([0, 1])\n",
        "\n",
        "    # # Check if U is unitary\n",
        "    if is_unitary(O):\n",
        "        print(\"Matrix O is unitary.\")\n",
        "    else:\n",
        "        print(\"Matrix O is not unitary.\")\n",
        "\n",
        "    # # Check if H is Hermitian\n",
        "    if is_hermitian(O):\n",
        "        print(\"Matrix O is Hermitian.\")\n",
        "    else:\n",
        "        print(\"Matrix O is not Hermitian.\")\n",
        "\n",
        "    # Compute eigenvalues\n",
        "    eigenvalues = eigenval_calculator(H)\n",
        "    print(f'The eigenvalues are {eigenvalues}')\n",
        "\n",
        "    # eigenvalues = eigenval_calculator(np.matmul(H,H))\n",
        "    # print(f'The eigenvalues are {eigenvalues}')\n",
        "\n",
        "    # Compute eigenvalues and eigenvectors for spectral decomp.\n",
        "    H_spec = spectral(O)\n",
        "    print(f'The spectral decomposition is {H_spec}')\n",
        "    clos = closure(O)\n",
        "    print(f'If identity, closure property is observed: {clos}')\n",
        "\n",
        "    # Verify that dot product remains invariant under U\n",
        "    if verify_dot_product_invariance(U, v1, v2):\n",
        "        print(\"Dot product is invariant under the unitary transformation.\")\n",
        "    else:\n",
        "        print(\"Dot product changes under the unitary transformation.\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "E8XI0X1PyCB0",
        "outputId": "ed90995a-9ed2-4905-a3cb-8dea06a52823"
      },
      "id": "E8XI0X1PyCB0",
      "execution_count": 13,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Matrix O is unitary.\n",
            "Matrix O is Hermitian.\n",
            "The eigenvalues are [3.+0.j 1.+0.j]\n",
            "The spectral decomposition is [[0. 1.]\n",
            " [1. 0.]]\n",
            "If identity, closure property is observed: [[1. 0.]\n",
            " [0. 1.]]\n",
            "Dot product is invariant under the unitary transformation.\n"
          ]
        }
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.12"
    },
    "colab": {
      "provenance": [],
      "include_colab_link": true
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}